use crate::ast::*;
use crate::error::{CompilerError, Result};
use crate::llvm_backend::LLVMBackend;
use inkwell::values::BasicValueEnum;

impl<'ctx> LLVMBackend<'ctx> {


    /// Generate Option method call
    pub(in crate::llvm_backend) fn generate_option_method_call(
        &mut self,
        method_name: &str,
        option_value: BasicValueEnum<'ctx>,
        option_type: &crate::ast::types::OptionType,
        arguments: &[Expression],
        location: &crate::error::Location,
    ) -> Result<BasicValueEnum<'ctx>> {
        match method_name {
            "is_some" => self.generate_option_is_some(option_value),
            "is_none" => self.generate_option_is_none(option_value),
            "unwrap" => self.generate_option_unwrap(option_value, option_type, location),
            "expect" => self.generate_option_expect(option_value, option_type, arguments, location),
            "unwrap_or" => {
                self.generate_option_unwrap_or(option_value, option_type, arguments, location)
            }
            "unwrap_or_else" => {
                self.generate_option_unwrap_or_else(option_value, option_type, arguments, location)
            }
            "map" => self.generate_option_map(option_value, option_type, arguments, location),
            "and_then" => {
                self.generate_option_and_then(option_value, option_type, arguments, location)
            }
            "or_else" => {
                self.generate_option_or_else(option_value, option_type, arguments, location)
            }
            "filter" => self.generate_option_filter(option_value, option_type, arguments, location),
            "and" => self.generate_option_and(option_value, option_type, arguments, location),
            "or" => self.generate_option_or(option_value, option_type, arguments, location),
            "xor" => self.generate_option_xor(option_value, option_type, arguments, location),
            "ok_or" => self.generate_option_ok_or(option_value, option_type, arguments, location),
            "ok_or_else" => {
                self.generate_option_ok_or_else(option_value, option_type, arguments, location)
            }
            "map_or" => self.generate_option_map_or(option_value, option_type, arguments, location),
            "map_or_else" => {
                self.generate_option_map_or_else(option_value, option_type, arguments, location)
            }
            _ => Err(CompilerError::internal(&format!(
                "Unknown Option method: {}",
                method_name
            ))),
        }
    }


    /// Generate Option method call with variable name (for mutable methods)
    pub(in crate::llvm_backend) fn generate_option_method_call_with_var(
        &mut self,
        method_name: &str,
        option_value: BasicValueEnum<'ctx>,
        option_type: &crate::ast::types::OptionType,
        arguments: &[Expression],
        location: &crate::error::Location,
        var_name: Option<&str>,
    ) -> Result<BasicValueEnum<'ctx>> {
        match method_name {
            "take" => self.generate_option_take(option_value, option_type, location, var_name),
            "replace" => self.generate_option_replace(
                option_value,
                option_type,
                arguments,
                location,
                var_name,
            ),
            _ => Err(CompilerError::internal(&format!(
                "Unknown mutable Option method: {}",
                method_name
            ))),
        }
    }

}
